﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.BizTalk.Adapter.Framework;
using System.Resources;
using System.Reflection;
using System.Xml;
using System.IO;
using Microsoft.Win32;
using Microsoft.BizTalk.Component.Interop;

namespace com.fluister.Biztalk0MQAdapter.DesignTime
{
    public class Biztalk0MQAdapter : IAdapterConfig, IStaticAdapterConfig, IAdapterConfigValidation
    {
        private static ResourceManager resourceManager = new ResourceManager("Biztalk0MQAdapterManagement.Biztalk0MQAdapterResource", Assembly.GetExecutingAssembly());


        protected string LocalizeSchema(string schema, ResourceManager resourceManager)
        {
            XmlDocument document = new XmlDocument();
            document.LoadXml(schema);

            XmlNodeList nodes = document.SelectNodes("/descendant::*[@_locID]");
            foreach (XmlNode node in nodes)
            {
                string locID = node.Attributes["_locID"].Value;
                node.InnerText = resourceManager.GetString(locID);
            }

            StringWriter writer = new StringWriter();
            document.WriteTo(new XmlTextWriter(writer));

            string localizedSchema = writer.ToString();
            return localizedSchema;
        }

        /// <summary>
        /// Returns the configuration schema as a string.
        /// (Implements IAdapterConfig)
        /// </summary>
        /// <param name="type">Configuration schema to return</param>
        /// <returns>Selected xsd schema as a string</returns>
        public string GetConfigSchema(ConfigType type)
        {
            switch (type)
            {
                case ConfigType.ReceiveHandler:
                    return LocalizeSchema(GetResource("Biztalk0MQAdapterManagement.ReceiveHandler.xsd"), resourceManager);

                case ConfigType.ReceiveLocation:
                    return LocalizeSchema(GetResource("Biztalk0MQAdapterManagement.ReceiveLocation.xsd"), resourceManager);

                case ConfigType.TransmitHandler:
                    return LocalizeSchema(GetResource("Biztalk0MQAdapterManagement.TransmitHandler.xsd"), resourceManager);

                case ConfigType.TransmitLocation:
                    return LocalizeSchema(GetResource("Biztalk0MQAdapterManagement.TransmitLocation.xsd"), resourceManager);

                default:
                    return null;
            }
        }

        /// <summary>
        /// Get the WSDL file name for the selected WSDL
        /// </summary>
        /// <param name="wsdls">place holder</param>
        /// <returns>An empty string[]</returns>
        public string[] GetServiceDescription(string[] wsdls)
        {
            string[] result = new string[1];
            result[0] = GetResource("Biztalk0MQAdapterManagement.service1.wsdl");
            return result;
        }

        /// <summary>
        /// Gets the XML instance of TreeView that needs to be rendered
        /// </summary>
        /// <param name="endPointConfiguration"></param>
        /// <param name="NodeIdentifier"></param>
        /// <returns>Location of TreeView xml instance</returns>
        public string GetServiceOrganization(IPropertyBag endPointConfiguration,
                                             string NodeIdentifier)
        {
            string result = GetResource("Biztalk0MQAdapterManagement.CategorySchema.xml");
            return result;
        }


        /// <summary>
        /// Acquire externally referenced xsd's
        /// </summary>
        /// <param name="xsdLocation">Location of schema</param>
        /// <param name="xsdNamespace">Namespace</param>
        /// <param name="XSDFileName">Schmea file name (return)</param>
        /// <returns>Outcome of acquisition</returns>
        public Result GetSchema(string xsdLocation,
                                string xsdNamespace,
                                out string xsdSchema)
        {
            xsdSchema = null;
            return Result.Continue;
        }

        /// <summary>
        /// Validate xmlInstance against configuration.  In this example it does nothing.
        /// </summary>
        /// <param name="type">Type of port or location being configured</param>
        /// <param name="xmlInstance">Instance value to be validated</param>
        /// <returns>Validated configuration.</returns>
        public string ValidateConfiguration(ConfigType configType,
            string xmlInstance)
        {
            string validXml = String.Empty;

            switch (configType)
            {
                case ConfigType.ReceiveHandler:
                    validXml = xmlInstance;
                    break;

                case ConfigType.ReceiveLocation:
                    validXml = ValidateReceiveLocation(xmlInstance);
                    break;

                case ConfigType.TransmitHandler:
                    validXml = xmlInstance;
                    break;

                case ConfigType.TransmitLocation:
                    validXml = ValidateTransmitLocation(xmlInstance);
                    break;
            }

            return validXml;
        }

        /// <summary>
        /// Helper to get resource from manafest.  Replace with 
        /// ResourceManager.GetString if .resources or
        /// .resx files are used for managing this assemblies resources.
        /// </summary>
        /// <param name="resource">Full resource name</param>
        /// <returns>Resource value</returns>
        private string GetResource(string resource)
        {
            string value = null;
            if (null != resource)
            {
                Assembly assem = this.GetType().Assembly;
                Stream stream = assem.GetManifestResourceStream(resource);
                StreamReader reader = null;

                using (reader = new StreamReader(stream))
                {
                    value = reader.ReadToEnd();
                }
            }

            return value;
        }

        /// <summary>
        /// Generate uri entry based on directory and fileMask values
        /// </summary>
        /// <param name="type">Type of port or location being configured</param>
        /// <param name="xmlInstance">Instance value to be validated</param>
        /// <returns>Validated configuration.</returns>
        private string ValidateReceiveLocation(string xmlInstance)
        {
            // Load up document
            XmlDocument document = new XmlDocument();
            document.LoadXml(xmlInstance);

            // Build up inner text
            StringBuilder builder = new StringBuilder();

            XmlNode sourceUrl = document.SelectSingleNode("Config/sourceUrl");
            // Ensure that the destination URL supplied is not empty
            if (sourceUrl == null || sourceUrl.InnerText == String.Empty)
                throw new ApplicationException("Transport properties validation failed.  Value for required adapter property \"Destination Url\" is not specified.");

            // This adapter only supports HTTP, it does not support HTTPS...
            if (!sourceUrl.InnerText.StartsWith("tcp://") &&
                !sourceUrl.InnerText.StartsWith("ipc://") &&
                !sourceUrl.InnerText.StartsWith("inproc://") &&
                !sourceUrl.InnerText.StartsWith("pgm://") &&
                !sourceUrl.InnerText.StartsWith("epgm://"))
                throw new ApplicationException("The Url must start with [tcp|ipc|inproc|pgm|epgm]://");

            XmlNode uri = document.SelectSingleNode("Config/uri");
            
            if (null == uri)
            {
                uri = document.CreateElement("uri");
                document.DocumentElement.AppendChild(uri);
            }

            uri.InnerText = sourceUrl.InnerText;

            return document.OuterXml;
        }

        /// <summary>
        /// Generate uri entry based on directory and fileName values
        /// </summary>
        /// <param name="type">Type of port or location being configured</param>
        /// <param name="xmlInstance">Instance value to be validated</param>
        /// <returns>Validated configuration.</returns>
        private string ValidateTransmitLocation(string xmlInstance)
        {
            // Load up document
            XmlDocument document = new XmlDocument();
            document.LoadXml(xmlInstance);

            // Build up inner text
            StringBuilder builder = new StringBuilder();

            XmlNode destinationUrl = document.SelectSingleNode("Config/destinationUrl");

            // Ensure that the destination URL supplied is not empty
            if (destinationUrl == null || destinationUrl.InnerText == String.Empty)
                throw new ApplicationException("Transport properties validation failed.  Value for required adapter property \"Destination Url\" is not specified.");

            // This adapter only supports HTTP, it does not support HTTPS...
            if (!destinationUrl.InnerText.StartsWith("tcp://") && 
                !destinationUrl.InnerText.StartsWith("ipc://") && 
                !destinationUrl.InnerText.StartsWith("inproc://") && 
                !destinationUrl.InnerText.StartsWith("pgm://") && 
                !destinationUrl.InnerText.StartsWith("epgm://"))
                throw new ApplicationException("The Url must start with [tcp|ipc|inproc|pgm|epgm]://");

            XmlNode uri = document.SelectSingleNode("Config/uri");
            if (null == uri)
            {
                uri = document.CreateElement("uri");
                document.DocumentElement.AppendChild(uri);
            }
            uri.InnerText = destinationUrl.InnerText;

            return document.OuterXml;
        }

        // debug code
        protected string GetSchemaFromFile(string name)
        {
            RegistryKey bts30 = Registry.LocalMachine.OpenSubKey("SOFTWARE").OpenSubKey("Microsoft").OpenSubKey("BizTalk Server").OpenSubKey("3.0");
            string installPath = (string)bts30.GetValue("InstallPath");
            string productLanguage = (string)bts30.GetValue("ProductLanguage");
            string fullName = installPath + productLanguage + "\\" + name;
            StreamReader reader = new StreamReader(fullName);

            string schema = reader.ReadToEnd();
            return schema;
        }
    } 
}
